package com.sxhuayuan.parking.plugin.invoice;

import com.sxhuayuan.parking.compenent.Message;
import com.sxhuayuan.parking.compenent.web.RespMessage;
import com.sxhuayuan.parking.entity.Invoice;
import com.sxhuayuan.parking.entity.ParkingLot;
import com.sxhuayuan.parking.exception.MyException;
import com.sxhuayuan.parking.exception.SystemException;
import com.sxhuayuan.parking.plugin.parking.bean.McardChargeOption;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.CompareToBuilder;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 发票系统插件
 * @author helong
 * @create 2019/8/29 17:17
 */
public abstract class InvoicePlugin implements Comparable<InvoicePlugin>, InitializingBean, DisposableBean {
	private static Logger log = LoggerFactory.getLogger(InvoicePlugin.class);

	private static CloseableHttpClient httpClient;

	private static final Map<String, String> HEADERS_JSON = new HashMap<>();

	private static Map<String, Map<String, McardChargeOption>> monthCardChargeOptionMap = new HashMap<>();

	/**
	 * connectionRequestTimeout: 从连接池中获取连接的超时时间，超过该时间未拿到可用连接<br>
	 * connectTimeout: 连接上服务器(握手成功)的时间，超出该时间抛出connect timeout <br>
	 * socketTimeout: 服务器返回数据(response)的时间，超过该时间抛出read timeout<br>
	 */
	static {
		List<Header> defaultHeaders = new ArrayList<>();
		defaultHeaders.add(new BasicHeader("accept", "*/*"));
		defaultHeaders.add(new BasicHeader("connection", "Keep-Alive"));
		// 连接最多等待6秒，无响应则断开
		RequestConfig config = RequestConfig.custom().setConnectTimeout(6000).setSocketTimeout(6000).build();
		httpClient = HttpClients.custom().setDefaultRequestConfig(config).setConnectionTimeToLive(300, TimeUnit.SECONDS).setDefaultHeaders(defaultHeaders).build();
		HEADERS_JSON.put("Content-Type", "application/json;charset=utf-8");
	}


	/** 插件id */
	public abstract String getId();

	/**
	 * 获取插件名称
	 */
	public abstract String getName();

	/**
	 * 获取二维码链接接口
	 */
	public abstract String getQrCodeUrl();

	/**
	 * 获取网址
	 */
	public abstract String getSiteUrl();

	/**
	 * 获取查询开票结果接口
	 */
	public abstract String getQueryInvoiceStateUrl();

	/** 向第三方系统请求开具发票
	 * @param invoice 退款记录信息
	 * @param parkingLot 车场
	 */
	public abstract String getInvoiceQrCode(Invoice invoice, ParkingLot parkingLot) throws SystemException;

	/** 第三方开票系统回调开票是否成功 */
	public abstract void invoiceCallback(HttpServletRequest request, HttpServletResponse response) throws Exception;

	/** 通过调第三方接口，查询开票是否成功,如果成功，在方法内部更改开票状态 */
	public abstract boolean queryInvoiceState(Invoice invoice);


	/**
	 * 获取请求编码方式
	 *
	 * @return
	 */
	public String getCharset() {
		return "utf-8";
	}

	/**
	 * POST请求，6秒超时
	 *
	 * @param url
	 *            URL
	 * @param parameterMap
	 *            请求参数
	 * @return 返回结果
	 */
	protected String post(String url, Map<String, Object> parameterMap) {
		Assert.hasText(url, "");
		String result = null;
		CloseableHttpResponse httpResponse = null;
		try {
			HttpPost httpPost = new HttpPost(url);
			List<NameValuePair> nameValuePairs = new ArrayList<>();
			if (parameterMap != null) {
				for (Map.Entry<String, Object> entry : parameterMap.entrySet()) {
					String name = entry.getKey();
					String value = ConvertUtils.convert(entry.getValue());
					if (StringUtils.isNotEmpty(name)) {
						nameValuePairs.add(new BasicNameValuePair(name, value));
					}
				}
			}
			httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, this.getCharset()));
			httpResponse = httpClient.execute(httpPost);
			if (httpResponse == null) {
				throw new MyException(RespMessage.Status.ERROR, Message.COMMON_SERVER_CONNECTION_FAILURE);
			}
			HttpEntity httpEntity = httpResponse.getEntity();
			result = EntityUtils.toString(httpEntity);
			EntityUtils.consume(httpEntity);
		} catch (IOException e) {
			log.error("", e);
			throw new MyException(RespMessage.Status.ERROR, Message.COMMON_SERVER_CONNECTION_FAILURE);
		} catch (Exception e) {
			log.error("", e);
		} finally {
			try {
				if (httpResponse != null) {
					httpResponse.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	/**
	 * GET请求，6秒超时
	 *
	 * @param url
	 *            URL
	 * @param parameterMap
	 *            请求参数
	 * @return 返回结果
	 */
	protected String get(String url, Map<String, Object> parameterMap) {
		Assert.hasText(url, "");
		String result = null;
		CloseableHttpResponse httpResponse = null;
		try {
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
			if (parameterMap != null) {
				for (Map.Entry<String, Object> entry : parameterMap.entrySet()) {
					String name = entry.getKey();
					String value = ConvertUtils.convert(entry.getValue());
					if (StringUtils.isNotEmpty(name)) {
						nameValuePairs.add(new BasicNameValuePair(name, value));
					}
				}
			}
			HttpGet httpGet = new HttpGet(url + (StringUtils.contains(url, "?") ? "&" : "?") + EntityUtils.toString(new UrlEncodedFormEntity(nameValuePairs, getCharset())));
			httpResponse = httpClient.execute(httpGet);
			if (httpResponse == null) {
				throw new MyException(RespMessage.Status.ERROR, Message.COMMON_SERVER_CONNECTION_FAILURE);
			}
			HttpEntity httpEntity = httpResponse.getEntity();
			result = EntityUtils.toString(httpEntity);
			EntityUtils.consume(httpEntity);
		} catch (IOException e) {
			log.error("", e);
			throw new MyException(RespMessage.Status.ERROR, Message.COMMON_SERVER_CONNECTION_FAILURE);
		} catch (Exception e) {
			log.error("", e);
		} finally {
			try {
				if (httpResponse != null) {
					httpResponse.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		if (this == obj) {
			return true;
		}
		InvoicePlugin other = (InvoicePlugin) obj;
		return new EqualsBuilder().append(getId(), other.getId()).isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder(17, 37).append(getId()).toHashCode();
	}

	@Override
	public int compareTo(InvoicePlugin invoicePlugin) {
		return new CompareToBuilder().append(getId(), invoicePlugin.getId()).toComparison();
	}

	@Override
	public void destroy() throws Exception {
		try {
			httpClient.close();
		} catch (Exception e) {
			log.error("", e);
		}
	}

	@Override
	public void afterPropertiesSet() throws Exception {

	}
}
